#pragma once

#include <iostream>
#include <string>
#include <pthread.h>
#include <vector>
#include <sstream>
#include <fstream>
#include <unordered_map>
#include "Socket.hpp"
#include "Log.hpp"

extern Log log;

const std::string wwwroot = "./wwwroot";      // web根目录
const std::string seq = "\r\n";               // 分隔符
const std::string homepage = "index.html";    // 首页

class HttpServer;

class ThreadData{
public:
    ThreadData(const int &sockfd, HttpServer *svr)
    : _sockfd(sockfd), httpsvr(svr)
    {}

public:
    int _sockfd;
    HttpServer *httpsvr;
};

class HttpRequest{
public:
    // 反序列化
    void Deserialize(std::string req){
        while(true){
            std::size_t pos = req.find(seq);
            if (pos == std::string::npos){
                break;
            }
            std::string cur = req.substr(0, pos);
            if (cur.empty()){
                break;
            }
            req_header.push_back(cur);
            req.erase(0, pos + seq.size());
        }
        text = req;
    }

    void DebugPrint(){
        for(auto &line : req_header){ 
            std::cout << "-----------------------" << std::endl;
            std::cout << line << std ::endl
                      << std::endl;
        }

        std::cout << "method: " << method << std::endl;
        std::cout << "url: " << url << std::endl;
        std::cout << "http_version: " << http_version << std::endl;
        std::cout << "file_path: " << file_path << std::endl;
        std::cout << text << std::endl;
    }

    void Parse(){
        std::stringstream ss(req_header[0]);
        ss >> method >> url >> http_version;
        file_path = wwwroot;                         // ./wwwroot
        if (url == "/" || url == "/index.html"){
            file_path += "/";
            file_path += homepage;                   // ./wwwroot/index.html
        }
        else{
            file_path += url;                        // ./wwwroot/...
        }

        std::size_t pos = file_path.rfind(".");
        if (pos == std::string::npos){
            suffix = ".html";
        }
        else{
            suffix = file_path.substr(pos);
        }
    }

public:
    std::vector<std::string> req_header;     // 请求报头的每一行存放到数组中
    std::string text;                        // 请求正文

    // 请求行解析之后的结果
    std::string method;
    std::string url;
    std::string http_version;
    std::string file_path;

    std::string suffix;                      // 后缀字符串
};

class HttpServer{
public:
    HttpServer(const uint16_t port)
    :_port(port)
    {
        content_type.insert({".html", "text/html"});
        content_type.insert({".png", "image/png"});
        content_type.insert({"jpg", "image/jpg"});
    }

    // 初始化服务器
    void InitServer(){
        _listensock.Socket();
        _listensock.Bind(_port);
        _listensock.Listen();
        log(INFO, "HttpServer Init ... Done");
    }

    // 启动服务器
    void StartServer(){
        while(true){
            std::string clientip;
            uint16_t clientport;
            int sockfd = _listensock.Accept(&clientip, &clientport);
            if (sockfd < 0){
                continue;
            }
            log(INFO, "httpserver get a connect, sockfd: %d", sockfd);

            ThreadData *td = new ThreadData(sockfd, this);
            pthread_t tid;
            pthread_create(&tid, nullptr, ThreadRun, td);
        }
    }

private:
    // 根据路径路径打开对应的的网页文件 获取响应正文部分
    static std::string ReadHtmlContent(const std::string &htmlpath){
        // std::ifstream in(htmlpath);
        // if (!in.is_open()){
        //     return "404";
        // }

        // std::string line;
        // std::string content;
        // while (std::getline(in, line)){
        //     content += line;
        // }
        // in.close();
        // return content;

        std::ifstream in(htmlpath, std::ios::binary);
        if(!in.is_open()){
            return "404";
        }
        in.seekg(0, std::ios_base::end);
        auto len = in.tellg();
        in.seekg(0, std::ios_base::beg);

        std::string content;
        content.resize(len);

        in.read((char *)content.c_str(), content.size());
        in.close();
        return content;
    }

    std::string SuffixToDesc(const std::string &suffix){
        auto iter = content_type.find(suffix);
        if(iter==content_type.end()){
            return content_type[".html"];
        }
        else{
            return content_type[suffix];
        }
    }

    void HttpHandler(const int &sockfd){
        char buffer[1024];
        ssize_t n = recv(sockfd, buffer, sizeof(buffer), 0);
        if(n > 0){
            buffer[n] = 0;
            std::cout << buffer << std::endl;           // 假设读取到的是一个完整的，独立的http请求
            HttpRequest req;
            req.Deserialize(buffer);                    // 先反序列化
            req.Parse();                                // 解析
            //req.DebugPrint();                         // 测试打印

            std::string text;                                           // 响应正文部分
            text = ReadHtmlContent(req.file_path);
            bool ok = true;
            if (text == "404"){
                ok = false;
                std::string err_file_path = wwwroot;
                err_file_path += "/err.html";
                text = ReadHtmlContent(err_file_path);
            }

            std::string response_line;                                   // 状态行
            if(ok){
                response_line = "HTTP/1.1 200 OK\r\n"; 
            }
            else{
                //response_line = "HTTP/1.0 404 Not Found\r\n";   
                response_line = "HTTP/1.0 302 Found\r\n";                // 临时重定向
            }

            std::string response_header = "Content-Length: ";            // 响应报头
            response_header += std::to_string(text.size());
            response_header += "\r\n";                                  
            // if(!ok){
            //     response_header += "Location: http://www.qq.com\r\n";   // 新地址的URL
            // }

            response_header += "Content-Type: ";
            response_header += SuffixToDesc(req.suffix);
            response_header += "\r\n";

            std::string blank_line = "\r\n";                            // 空行分隔符

            // 构建响应字符串
            std::string response = response_line;
            response += response_header;
            response += blank_line;
            response += text;
            // 发送响应
            ssize_t k = send(sockfd, response.c_str(), response.size(), 0);
        }
        close(sockfd);
    }

    static void *ThreadRun(void *args){
        pthread_detach(pthread_self());    // 线程分离
        ThreadData *td = static_cast<ThreadData *>(args);
        td->httpsvr->HttpHandler(td->_sockfd);
        delete td;                         // 释放线程信息对象
        return nullptr;
    }

    ~HttpServer()
    {}
private:
    uint16_t _port;
    MySocket _listensock;
    std::unordered_map<std::string, std::string> content_type;
};